home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / snz128s / src / expire.c < prev    next >
C/C++ Source or Header  |  1994-06-01  |  21KB  |  863 lines

  1. /*
  2.     SNEWS 2.0
  3.  
  4.     EXPIRE - expire news database articles by number of days since rx'd
  5.  
  6.  
  7.     Copyright (C) 1991  John McCombs, PO Box 2708, Christchurch, NEW ZEALAND
  8.                         john@ahuriri.gen.nz
  9.  
  10.     This program is free software; you can redistribute it and/or modify
  11.     it under the terms of the GNU General Public License, version 1, as
  12.     published by the Free Software Foundation.
  13.  
  14.     This program is distributed in the hope that it will be useful,
  15.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.     GNU General Public License for more details.
  18.  
  19.     See the file COPYING, which contains a copy of the GNU General
  20.     Public License.
  21.  
  22.     USAGE:  expires [<days>]
  23.  
  24.  */
  25.  
  26. /*---------------------------- Source Control ------------------------------*/
  27.  
  28. /*
  29.  * $Id: EXPIRE.C,v 1.2 1994/02/05 18:46:56 gbj Exp user $
  30.  */
  31.  
  32. /****************************************************************************
  33. *   02 Jul 92   1.2     GT  Change history file name.                       *
  34. *   01 Sep 92   1.3    MSM  Selective expire                                *
  35. *   21 Nov 92   1.4    MSM  Colour Support                                  *
  36. *   16 Dec 92   1.5    MSM  Expiry of snews history file                    *
  37. *   20 Dec 92   1.6    MSM  Archiving of Newsgroups                         *
  38. *   31 May 93   1.7    MSM  Achive file problem fixed                       *
  39. *                           Token in archive file corrected                 *
  40. *                           Snews 2.0                                       *
  41. *   19 Jun 93   1.8    MSM  Memory allocation / free routines corrected     *
  42. *   26 Sep 93   1.9    MSM  Last item bug in read_expire fixed              *
  43. *   18 Oct 93   1.10   MSM  Minor long int corrections                      *
  44. *                           Return codes added                              *
  45. *    5 Dec 93   1.11   MSM  Subject limited to 128 characters               *
  46. *    2 Apr 94   1.12   MSM  Check added for uot of time sequence articles   *
  47. *                (with thanks to ubik.demon.co.uk)            *
  48. *                If an article is found to be out of sequence    *
  49. *                its time stamp is corrected                *
  50. ****************************************************************************/
  51.  
  52. #include "defs.h"
  53. #include "expire.h"
  54. #include "locking.h"
  55. #include "screen.h"
  56.  
  57. #include <io.h>
  58. #include <fcntl.h>
  59. #include <ctype.h>
  60.  
  61. #ifdef ATARI
  62. #    include "st.h"
  63. #endif
  64.  
  65. #ifndef __TURBOC__
  66. #ifndef ATARI
  67. #define BLACK 0
  68. #define LIGHTGRAY 7
  69. #endif
  70. #endif
  71.  
  72. extern int      scr_x, scr_y;
  73.  
  74. void            scroll_up(int);
  75.  
  76. int             selective;
  77.  
  78. INFO            my_stuff;
  79.  
  80. EXP_DATA       *exp_entry, *exp_first;
  81.  
  82. /*------------------------------- main --------------------------------*/
  83. int             main(int argc, char *argv[])
  84. {
  85.  
  86.     /*
  87.      * This routine expires the news database thus:
  88.      * - copy the index and text files into new ones, omitting the old ones
  89.      * - update the article counters
  90.      * - delete the old articles and rename the new files
  91.      * - print the totals
  92.      * 
  93.      * TODO: It's too big a hunk break it up
  94.      */
  95.  
  96.     ACTIVE         *gp, *head;
  97.     char           *fn, buf[256], buf2[256], subject[256], arc_file[65];
  98.     struct stat     st;
  99.     time_t          current;
  100.     long            secs, i, offset;
  101.     int             days;
  102.     int             ch;
  103.     int             no_space;
  104.     int             flag_s;
  105.     int             ret_code;
  106.     long            art_time;
  107.     long        prev_art_time;
  108.     long            where;
  109.     long            exp_default;
  110.  
  111.     FILE           *index;
  112.     FILE           *old_index;
  113.     FILE           *text;
  114.     FILE           *old_text;
  115.     FILE           *arch;
  116.  
  117.     int             articles;
  118.     int             articles_deleted;
  119.     int             articles_archived;
  120.     int             gp_art;
  121.     int             gp_art_deleted;
  122.     int             gp_art_archived;
  123.     int        gp_flag;
  124.  
  125.     long            total_bytes;
  126.     long            total_bytes_deleted;
  127.     long            total_bytes_archived;
  128.     long            gp_bytes;
  129.     long            gp_bytes_deleted;
  130.     long            gp_bytes_archived;
  131.  
  132.  
  133.     articles = 0;
  134.     articles_deleted = 0;
  135.     articles_archived = 0;
  136.  
  137.     total_bytes = 0l;
  138.     total_bytes_deleted = 0l;
  139.     total_bytes_archived = 0l;
  140.     arc_file[0] = '\0';
  141.  
  142.     if (!load_stuff()) {
  143.         fprintf(stderr, "expire: couldn't read rc info\n");
  144.     }
  145.  
  146.     v_init(my_stuff.directvideo);          /* initialise bios video package */
  147.  
  148.     fprintf(stderr, "Demon Internet Services Simple News v%d.%2d [build %d]\n",
  149.         rmj, rmm, rup);
  150.     fprintf(stderr, "Expire Old News\n\n");
  151.     
  152.     if (argc <= 2) {
  153.  
  154.         head = load_active_file();
  155.  
  156.         time(¤t);
  157.  
  158.         selective = TRUE;
  159.  
  160.         if (argc == 2) {
  161.             if (isdigit(argv[1][0]) && (atoi(argv[1]) >= 0)) {
  162.                 days = atoi(argv[1]);
  163.                 secs = (long) days * 86400l;
  164.                 selective = FALSE;
  165.                 exp_default = secs;
  166.                 gotoxy(1, 3);
  167.                 printf("expire: Retain %d days in all newsgroups ? ", days);
  168.                 ch = getch();
  169.                 putch(ch);
  170.                 putch('\n');
  171.                 ch = tolower(ch);
  172.                 if (ch != 'y')
  173.                     exit(1);
  174.             }
  175.             else {
  176.                 fprintf(stderr, "expire: Invalid day count specified.\n");
  177.                 exit(1);
  178.             }
  179.         }
  180.         else {
  181.  
  182.             if (load_expire() == FALSE) {
  183.                 fprintf(stderr, "expire: Error loading expiry data.\n");
  184.                 exit(1);
  185.             }
  186.  
  187.             if (read_expire("[DEFAULT]", &exp_default, arc_file) == FALSE) {
  188.                 fprintf(stderr, "expire: Unable to find default expire item [default].\n");
  189.                 exit(1);
  190.             }
  191.         }
  192.  
  193.         gp = head;
  194.  
  195.         clrscr();
  196.  
  197.         textbackground(textb);
  198.         textcolor(textf);
  199.         clrscr();
  200.         textbackground(headb);
  201.         textcolor(headf);
  202.         clreol();
  203.         printf("NEWSGROUP                           : EXPIRE      ARTICLES        REMOVED       \r\n");
  204.         clreol();
  205.         textbackground(textb);
  206.         textcolor(textf);
  207.         printf("\r\n");
  208.         clreol();
  209.  
  210.         while (gp != NULL) {
  211.  
  212.             no_space = FALSE;
  213.  
  214.             gp_art = 0;
  215.             gp_art_deleted = 0;
  216.             gp_art_archived = 0;
  217.             gp_bytes = 0l;
  218.             gp_bytes_deleted = 0l;
  219.             gp_bytes_archived = 0l;
  220.             gp_flag = FALSE;
  221.  
  222.             if ((gp->hi_num - gp->lo_num) > 0l) {
  223.  
  224.                 /*
  225.                  * Open all the files.  First the old ones, then the new
  226.                  */
  227.  
  228.                 fn = make_news_group_name(gp->group);
  229.                 prev_art_time = 0l;
  230.  
  231.                 if (selective) {
  232.                     if (read_expire(gp->group, &secs, arc_file) == FALSE)
  233.                         secs = exp_default;
  234.                     if (secs < 0l)
  235.                         secs = -1l;
  236.                 }
  237.                 stat(fn, &st);
  238.                 if (*arc_file == '\0')
  239.                     gp_bytes_deleted = st.st_size;
  240.                 else
  241.                     gp_bytes_archived = st.st_size;
  242.  
  243.                 if ((old_text = fopen(fn, "rb")) == NULL)
  244.                     crash("can't open old text", fn);
  245. #ifdef ATARI
  246.                 setvbuf(old_text, NULL, _IOFBF, 32767);
  247. #else
  248.                 setvbuf(old_text, NULL, _IOFBF, 16384);
  249. #endif
  250.                 sprintf(buf, "%s.IDX", fn);
  251.                 if ((old_index = fopen(buf, "rb")) == NULL)
  252.                     crash("can't open old index", buf);
  253.  
  254.                 sprintf(buf, "%s.NEW", fn);
  255.                 if ((text = fopen(buf, "wb")) == NULL)
  256.                     crash("can't create new text", buf);
  257. #ifdef ATARI
  258.                 setvbuf(text, NULL, _IOFBF, 32767);
  259. #else
  260.                 setvbuf(text, NULL, _IOFBF, 16384);
  261. #endif
  262.                 sprintf(buf, "%s.NDX", fn);
  263.                 if ((index = fopen(buf, "wb")) == NULL)
  264.                     crash("can't create new index", buf);
  265.  
  266.                 if (selective && (*arc_file != '\0')) {
  267.                     if ((arch = fopen(arc_file, "at")) == NULL)
  268.                         crash("can't open archive", arc_file);
  269.                 }
  270.                 /* numbers go chronologically */
  271.                 for (i = (gp->lo_num) + 1l; i <= gp->hi_num; i++) {
  272.  
  273.                     fgets(buf, 255, old_index);
  274.                     if (i != atol(buf + 9)) {
  275.                         fprintf(stderr, "\nexpire: In %s article %ld found when %ld"
  276.                                 " expected\n", gp->group, atol(buf + 9), i);
  277.                         exit(1);
  278.                     }
  279.  
  280.                     /* get the time the article was processed */
  281.                     art_time = atol(buf + 18);
  282.                     if ((gp_flag == FALSE) &&
  283.                         (((long) current - art_time) > secs) && (secs >= 0l)) {
  284.  
  285.                         /*
  286.                          * Older than req'd - just count the totals
  287.                          */
  288.  
  289.                         if (*arc_file == '\0')
  290.                             gp_art_deleted++;
  291.                         else
  292.                             gp_art_archived++;
  293.  
  294.                         gp->lo_num++;
  295.                         update_active_entry(gp);
  296.  
  297.                         if (*arc_file != '\0') {
  298.                             where = ftell(text);
  299.                             offset = atol(buf);
  300.                             fseek(old_text, offset, SEEK_SET);
  301.                             if (fputs("\n#! rnews\n", arch) == EOF) {
  302.                                 no_space = TRUE;
  303.                                 break;
  304.                             }
  305.                             while (fgets(buf, 255, old_text)) {
  306.                                 if (strnicmp(buf, "@@@@END", 7) != 0) {
  307.                                     if (fputs(buf, arch) == EOF) {
  308.                                         no_space = TRUE;
  309.                                         break;
  310.                                     }
  311.                                 }
  312.                                 else
  313.                                     break;
  314.                             }
  315.                         }
  316.                     }
  317.                     else {
  318.  
  319.                         /*
  320.                          * Younger than limit, so keep the article
  321.                          */
  322.                         where = ftell(text);
  323.                         gp_flag = TRUE;
  324.  
  325.                         /* copy to new file */
  326.                         offset = atol(buf);
  327.                         flag_s = 0;
  328.                         fseek(old_text, offset, SEEK_SET);
  329.                         while (fgets(buf, 255, old_text)) {
  330.  
  331.                             if ((strnicmp(buf, "Subject:", 8) == 0) && (flag_s == 0)) {
  332.                                 flag_s = 1;
  333.                                 if (strlen(buf) > 136) {
  334.                                     buf[136] = '\n';
  335.                                     buf[137] = '\0';
  336.                                 }
  337.                                 strcpy(subject, buf + 8);
  338.                             }
  339.                             if (fputs(buf, text) == EOF) {
  340.                                 no_space = TRUE;
  341.                                 break;
  342.                             }
  343.                             if (strnicmp(buf, "@@@@END", 7) == 0)
  344.                                 break;
  345.                         }
  346.  
  347.                         /* save the header info */
  348.                         if (prev_art_time != 0) {
  349.                             if (art_time < prev_art_time)
  350.                                 art_time = prev_art_time;
  351.                         }
  352.                         fprintf(index, "%08ld %08ld %09ld %s", where, i,
  353.                                 art_time, subject);
  354.                         prev_art_time = art_time;
  355.                     }
  356.  
  357.                     if (no_space)
  358.                         break;
  359.                 }
  360.  
  361.                 /*
  362.                  * Close and rename the files
  363.                  */
  364.  
  365.                 fclose(old_text);
  366.                 fclose(old_index);
  367.                 fclose(text);
  368.                 fclose(index);
  369.                 if (*arc_file != '\0')
  370.                     fclose(arch);
  371.  
  372.                 fn = make_news_group_name(gp->group);
  373.  
  374.                 /* out of disk on expire, delete the temp files */
  375.  
  376.                 if (no_space) {
  377.                     printf("expire: Disk error expiring %s\n", gp->group);
  378.                     sprintf(buf2, "%s.NEW", fn);
  379.                     unlink(buf2);
  380.                     sprintf(buf2, "%s.NDX", fn);
  381.                     unlink(buf2);
  382.                 }
  383.                 else {
  384.                     unlink(fn);
  385.                     sprintf(buf2, "%s.NEW", fn);
  386.                     stat(buf2, &st);
  387.                     gp_bytes = st.st_size;
  388.                     rename(buf2, fn);
  389.  
  390.                     sprintf(buf, "%s.IDX", fn);
  391.                     unlink(buf);
  392.                     sprintf(buf2, "%s.NDX", fn);
  393.                     rename(buf2, buf);
  394.                 }
  395.  
  396.                 /* print all groups with articles */
  397.  
  398.                 gp_art = (int) (gp->hi_num - gp->lo_num);
  399.                 if (*arc_file == '\0')
  400.                     gp_bytes_deleted -= gp_bytes;
  401.                 else
  402.                     gp_bytes_archived -= gp_bytes;
  403.  
  404.                 articles += gp_art;
  405.                 total_bytes += gp_bytes;
  406.                 if (*arc_file == '\0') {
  407.                     articles_deleted += gp_art_deleted;
  408.                     total_bytes_deleted += gp_bytes_deleted;
  409.                 }
  410.                 else {
  411.                     articles_archived += gp_art_archived;
  412.                     total_bytes_archived += gp_bytes_archived;
  413.                 }
  414.                 if ((gp_art > 0) || (gp_art_deleted > 0) || (gp_art_archived > 0)) {
  415.  
  416.                     if (gp_art_deleted > 0)
  417.                         printf("%-35s : %4d     %4d %5ldKb    %4d %5ldKb\n",
  418.                                gp->group,
  419.                                (int) (secs / 86400l),
  420.                                gp_art, (gp_bytes + 500l) / 1000l,
  421.                                gp_art_deleted, (gp_bytes_deleted + 500l) / 1000l);
  422.  
  423.                     if (gp_art_archived > 0)
  424.                         printf("%-35s : %4d     %4d %5ldKb    %4d %5ldKb  A\n",
  425.                                gp->group,
  426.                                (int) (secs / 86400l),
  427.                                gp_art, (gp_bytes + 500l) / 1000l,
  428.                                gp_art_archived, (gp_bytes_archived + 500l) / 1000l);
  429.  
  430.                     if ((gp_art_deleted < 1) && (gp_art_archived < 1)) {
  431.                         if ((secs > 315300000l) || (secs < 0l))
  432.                             ch = -1;
  433.                         else
  434.                             ch = (int) (secs / 86400l);
  435.                         printf("%-35s : %4d     %4d %5ldKb\n",
  436.                                gp->group,
  437.                                ch,
  438.                                gp_art, (gp_bytes + 500l) / 1000l);
  439.                     }
  440.                     if (scr_y == scr_rows)
  441.                         scroll_up(3);
  442.                 }
  443.             }
  444.             gp = gp->next;
  445.         }
  446.  
  447.         close_active_file();
  448.  
  449.         scroll_up(3);
  450.         scroll_up(3);
  451.         scroll_up(3);
  452.  
  453.         gotoxy(1, scr_rows - 1);
  454.  
  455.         printf("Expiring snews history file \"history.snw\" ...\n");
  456.  
  457.         secs = exp_default;
  458.         expire_history(current, secs);
  459.  
  460.         if (selective) {
  461.  
  462.             scroll_up(3);
  463.             scroll_up(3);
  464.             scroll_up(3);
  465.  
  466.             gotoxy(1, scr_rows - 1);
  467.  
  468.             printf("Processing nntp history file \"history\" ...\n");
  469.  
  470.             scroll_up(3);
  471.             scroll_up(3);
  472.             gotoxy(1, scr_rows - 1);
  473.  
  474.             if (read_expire("[TAIL]", &exp_default, arc_file) == TRUE)
  475.                 nntp_tail(exp_default);
  476.             else {
  477.                 if (read_expire("[COPY]", &exp_default, arc_file) == TRUE)
  478.                     nntp_copy();
  479.             }
  480.         }
  481.         exp_free();
  482.  
  483. #ifndef ATARI
  484.         textbackground(BLACK);
  485.         textcolor(LIGHTGRAY);
  486.         
  487.         clrscr();
  488.  
  489.         gotoxy(1, 1);
  490. #endif
  491.  
  492.         printf("\n\nexpire: Processing Summary...\n\n");
  493.         printf("\t%7ld articles deleted     \n"
  494.                "\t%7ld articles archived    \n"
  495.                "\t%7ld Kb deleted           \n"
  496.                "\t%7ld Kb archived          \n"
  497.                "\t%7ld articles remaining   \n"
  498.                "\t%7ld Kb of text remaining \n",
  499.                articles_deleted,
  500.                articles_archived,
  501.                (total_bytes_deleted + 500l) / 1000l,
  502.                (total_bytes_archived + 500l) / 1000l,
  503.                articles,
  504.                (total_bytes + 500l) / 1000l);
  505.  
  506.         gotoxy(1, scr_rows - 5);
  507.  
  508.     ret_code = 0;
  509.     }
  510.     else {
  511.         fprintf(stderr, "usage:  expire [<days>]\n");
  512.         ret_code = 1;
  513.     }
  514. #ifdef ATARI
  515.     printf("\033q");
  516.     gotoxy(1, scr_rows);
  517.     printf("\n\n");
  518. #endif
  519.     return ret_code;
  520. }
  521.  
  522.  
  523. /*----------------------------------------------------------------------*/
  524. void            crash(char *msg, char *fn)
  525. {
  526.  
  527.     /*
  528.      * Abort if file open error
  529.      */
  530.  
  531.     fprintf(stderr, "\nexpire: %s, %s\n", msg, fn);
  532.     exit(1);
  533. }
  534.  
  535.  
  536. /*--------------------------- expire history entries --------------------*/
  537. void            expire_history(long current, long secs)
  538. {
  539.     FILE           *hist_file, *new_hist_file;
  540.     long            age, test, life;
  541.     char            buf[512], buf2[512], buf3[512], arc_file[65], *newsgroup, *p;
  542.     int             flag;
  543.     size_t          bufsize;
  544.  
  545.     /* open the files */
  546.     sprintf(buf, "%shistory.snw", my_stuff.news_dir);
  547.     if ((hist_file = fopen(buf, "rb")) == NULL) {
  548.         fprintf(stderr, "expire: cannot open file %s for input\n", buf);
  549.         exit(1);
  550.     }
  551.  
  552.     for (bufsize = (size_t) 32767U;
  553.          setvbuf(hist_file, NULL, _IOFBF, bufsize) != 0 && bufsize > 512;
  554.          bufsize /= 2);
  555.  
  556.     sprintf(buf, "%shistory.new", my_stuff.news_dir);
  557.     if ((new_hist_file = fopen(buf, "wb")) == NULL) {
  558.         fprintf(stderr, "expire: cannot open file %s for output\n", buf);
  559.         exit(1);
  560.     }
  561.  
  562.     if (!selective) {
  563.         while (fgets(buf, 255, hist_file) != NULL) {
  564.             sscanf(buf, "%*s %ld", &age);
  565.             if ((current - age) < secs) {
  566.                 fputs(buf, new_hist_file);
  567.             }
  568.         }
  569.     }
  570.     else {
  571.         while (fgets(buf, 255, hist_file) != NULL) {
  572.             test = secs;
  573.             sscanf(buf, "%*s %ld", &age);
  574.             strcpy(buf2, buf);
  575.             p = strtok(buf2, " \n\r");
  576.             strcpy(buf3, p);              /* Article ID */
  577.             p = strtok(NULL, " \n\r");
  578.             strcat(buf3, " ");
  579.             strcat(buf3, p);              /* Posting Time */
  580.             flag = FALSE;
  581.             while ((p = strtok(NULL, " \n\r")) != NULL) {
  582.                 if ((*p == '\n') || (*p == '\r'))
  583.                     break;
  584.                 newsgroup = p;
  585.                 p = strtok(NULL, " \n\r");
  586.                 if (read_expire("[LIFE]", &life, arc_file) == FALSE) {
  587.                     life = -1;
  588.                 }
  589.                 if (read_expire(newsgroup, &test, arc_file) == FALSE) {
  590.                     test = secs;
  591.                 }
  592.                 else {
  593.                     if (test < 0l)
  594.                         test = -1l;
  595.                 }
  596.                 if ((test == -1l) && (life != -1l)) {
  597.                     test = life;
  598.                 }
  599.                 if ((test > life) && (life != -1l))
  600.                     test = life;
  601.                 if ((test < 0l) || ((current - age) < test)) {
  602.                     strcat(buf3, " ");
  603.                     strcat(buf3, newsgroup);
  604.                     strcat(buf3, " ");
  605.                     strcat(buf3, p);
  606.                     flag = TRUE;
  607.                 }
  608.             }
  609.  
  610.             if (flag == TRUE) {
  611.                 strcat(buf3, "  \n");
  612.                 fputs(buf3, new_hist_file);
  613.             }
  614.         }
  615.     }
  616.  
  617.     fclose(hist_file);
  618.     fclose(new_hist_file);
  619.  
  620.     sprintf(buf, "%shistory.bak", my_stuff.news_dir);
  621.     unlink(buf);
  622.     sprintf(buf2, "%shistory.snw", my_stuff.news_dir);
  623.     rename(buf2, buf);
  624.     sprintf(buf, "%shistory.new", my_stuff.news_dir);
  625.     rename(buf, buf2);
  626.     sprintf(buf, "%shistory.bak", my_stuff.news_dir);
  627.     unlink(buf);
  628.  
  629. }
  630.  
  631. /*---------------------- Load the expiry data to memory ------------------*/
  632.  
  633. int             load_expire()
  634. {
  635.  
  636.     char            buf[80], buf2[80], *p;
  637.     FILE           *data;
  638.  
  639.     sprintf(buf, "%sexpire.dat", my_stuff.news_dir);
  640.     if ((data = fopen(buf, "rt")) == NULL) {
  641.         fprintf(stderr, "expire: Data file %sexpire.dat not found.\n",
  642.                 my_stuff.news_dir);
  643.         exit(1);
  644.     }
  645.  
  646.     while (fgets(buf, 80, data) != NULL) {
  647.         if (buf[0] == '\x1a')
  648.             break;
  649.         if ((buf[0] == '#') || (buf[0] == '\n'))
  650.             continue;
  651.         strcpy(buf2, buf);
  652.         if ((p = strtok(buf2, " ,\t\n\r")) == NULL) {
  653.             fclose(data);
  654.             return FALSE;
  655.         }
  656.  
  657.         if (exp_first == NULL) {
  658.             exp_first = (EXP_DATA *) malloc(sizeof(EXP_DATA));
  659.             if (exp_first == NULL) {
  660.                 fprintf(stderr, "expire: Out of memory.\n");
  661.                 exit(1);
  662.             }
  663.         exp_first->next = NULL;
  664.         exp_entry = exp_first;
  665.         }
  666.         else {
  667.             exp_entry->next = (EXP_DATA *) malloc(sizeof(EXP_DATA));
  668.             if (exp_entry->next == NULL) {
  669.                 fprintf(stderr, "expire: Out of memory.\n");
  670.                 exit(1);
  671.             }
  672.             exp_entry = exp_entry->next;
  673.             exp_entry->next = NULL;
  674.         }
  675.         
  676.         exp_entry->flag = FALSE;
  677.         strcpy(exp_entry->group, buf2);
  678.         if (exp_entry->group[strlen(exp_entry->group) - 1] == '*') {
  679.             exp_entry->group[strlen(exp_entry->group) - 1] = '\0';
  680.             exp_entry->flag = TRUE;
  681.         }
  682.  
  683.         if ((p = strtok(NULL, " ,\t\r\n")) == NULL) {
  684.             fclose(data);
  685.             return FALSE;
  686.         }
  687.  
  688.         exp_entry->days = atoi(p);
  689.         if ((p = strtok(NULL, " ,\t\r\n")) != NULL) {
  690.             strcpy(exp_entry->archive, p);
  691.         }
  692.         else {
  693.             strcpy(exp_entry->archive, "\0");
  694.         }
  695.     }
  696.     fclose(data);
  697.     return TRUE;
  698. }
  699.  
  700. /*-------------------------- Search expiry data struct --------------------*/
  701.  
  702. int             read_expire(char *target, long *len, char *arc)
  703. {
  704.  
  705.     char            group[80];
  706.     int             days, match, test, flag;
  707.  
  708.     match = 0;
  709.  
  710.     exp_entry = exp_first;
  711.  
  712.     arc[0] = '\0';
  713.  
  714.     while (exp_entry != NULL) {
  715.         flag = exp_entry->flag;
  716.  
  717.         strcpy(group, exp_entry->group);
  718.  
  719.         days = exp_entry->days;
  720.  
  721.         test = strlen(group);
  722.  
  723.         if ((test > match) && (flag)) {
  724.             if (strnicmp(target, group, test) == 0) {
  725.                 *len = (long) days *86400l;
  726.  
  727.                 strcpy(arc, exp_entry->archive);
  728.                 match = test;
  729.             }
  730.         }
  731.         else {
  732.             if (stricmp(target, group) == 0) {
  733.                 *len = (long) days *86400l;
  734.  
  735.                 strcpy(arc, exp_entry->archive);
  736.                 match = test;
  737.             }
  738.         }
  739.         exp_entry = exp_entry->next;
  740.     }
  741.  
  742.     if (match != 0) {
  743.         return TRUE;
  744.     }
  745.  
  746.     return FALSE;
  747. }
  748.  
  749. /*------------------------ Release Expire Data Memory ---------------------*/
  750.  
  751. void            exp_free()
  752. {
  753.  
  754.     EXP_DATA      *exp_next;
  755.  
  756.     exp_entry = exp_first;
  757.  
  758.     while (exp_entry != NULL) {
  759.         exp_next = exp_entry->next;
  760.         free(exp_entry);
  761.         exp_entry = exp_next;
  762.     }
  763.  
  764. }
  765.  
  766. /*-------------------- Deal with the NNTP History File --------------------*/
  767.  
  768. void            nntp_tail(long size)
  769. {
  770.  
  771.     long            start, lines, count;
  772.     char            buf[256], nntpfile[80], backfile[80], newfile[80];
  773.     FILE           *hf, *nf;
  774.     size_t          bufsize;
  775.  
  776.     lines = size / 86400l;
  777.  
  778.     printf("Removing all except last %ld lines from NNTP history.\n", lines);
  779.     sprintf(nntpfile, "%shistory", my_stuff.nntp_dir);
  780.     sprintf(backfile, "%shistory.bak", my_stuff.nntp_dir);
  781.     sprintf(newfile, "%shistory.new", my_stuff.nntp_dir);
  782.  
  783.     if ((hf = fopen(nntpfile, "rt")) == NULL) {
  784.         fprintf(stderr, "expire: unable to open nntp history file.\n");
  785.         exit(1);
  786.     }
  787.  
  788.     for (bufsize = (size_t) 32767U;
  789.          setvbuf(hf, NULL, _IOFBF, bufsize) != 0 && bufsize > 512;
  790.          bufsize /= 2);
  791.  
  792.     count = 0;
  793.     while (fgets(buf, 256, hf) != NULL)
  794.         count++;
  795.     rewind(hf);
  796.     if (count < lines) {                  /* nothing to do */
  797.         fclose(hf);
  798.         return;
  799.     }
  800.     start = count - lines;
  801.  
  802.     if ((nf = fopen(newfile, "wt")) == NULL) {
  803.         fprintf(stderr, "expire: Unable to create new nntp history.\n");
  804.         exit(1);
  805.     }
  806.  
  807.     count = 0;
  808.     while (fgets(buf, 255, hf) != NULL)
  809.         if (++count > start)
  810.             fputs(buf, nf);
  811.  
  812.     fclose(hf);
  813.     fclose(nf);
  814.  
  815.     unlink(backfile);
  816.     rename(nntpfile, backfile);
  817.     rename(newfile, nntpfile);
  818.  
  819. }
  820.  
  821. /*------------------------------ Copy Snews to nntp ------------------------*/
  822.  
  823. void            nntp_copy()
  824. {
  825.  
  826.     char            buf[256], snewsfile[80], nntpfile[80], newfile[80], backfile[80];
  827.     char           *p;
  828.     FILE           *sf, *nf;
  829.     size_t          bufsize;
  830.  
  831.     printf("Copying Snews History to NNTP history.\n");
  832.     sprintf(snewsfile, "%shistory.snw", my_stuff.news_dir);
  833.     sprintf(nntpfile, "%shistory", my_stuff.nntp_dir);
  834.     sprintf(newfile, "%shistory.new", my_stuff.nntp_dir);
  835.     sprintf(backfile, "%shistory.bak", my_stuff.nntp_dir);
  836.  
  837.     if ((sf = fopen(snewsfile, "rt")) == NULL) {
  838.         fprintf(stderr, "expire: Unable to open snews history.\n");
  839.         exit(1);
  840.     }
  841.  
  842.     for (bufsize = (size_t) 32767U;
  843.          setvbuf(sf, NULL, _IOFBF, bufsize) != 0 && bufsize > 512;
  844.          bufsize /= 2);
  845.  
  846.     if ((nf = fopen(newfile, "wt")) == NULL) {
  847.         fprintf(stderr, "expire: Unable to create new nntp history.\n");
  848.         exit(1);
  849.     }
  850.  
  851.     while (fgets(buf, 255, sf) != NULL) {
  852.         p = strtok(buf, " \t\n\r");
  853.         fputs(p, nf);
  854.         fputs("\n", nf);
  855.     }
  856.  
  857.     fclose(nf);
  858.     fclose(sf);
  859.     unlink(backfile);
  860.     rename(nntpfile, backfile);
  861.     rename(newfile, nntpfile);
  862. }
  863.